package com.vhall.component.service.account.impl;

import cn.hutool.crypto.digest.DigestAlgorithm;
import cn.hutool.crypto.digest.Digester;
import cn.hutool.crypto.digest.MD5;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.vhall.component.dao.account.AccountAdminsMapper;
import com.vhall.component.entity.account.AdminsEntity;
import com.vhall.component.entity.account.vo.AdminAuthLogOutReqVO;
import com.vhall.component.entity.account.vo.AdminAuthLoginReqVO;
import com.vhall.component.entity.account.vo.AdminAuthLoginRspVO;
import com.vhall.component.entity.rbac.vo.ActionsVO;
import com.vhall.component.entity.rbac.vo.MenuesVO;
import com.vhall.component.entity.rbac.vo.RoleVO;
import com.vhall.component.framework.common.exception.BusinessException;
import com.vhall.component.framework.common.support.UserTicketVO;
import com.vhall.component.plugin.common.constant.AccountConstant;
import com.vhall.component.plugin.common.constant.RedisKey;
import com.vhall.component.plugin.common.exception.BizErrorCode;
import com.vhall.component.plugin.common.support.TokenThreadLocal;
import com.vhall.component.plugin.common.thrift.common.UserTicketWrapper;
import com.vhall.component.plugin.common.utils.Constants;
import com.vhall.component.plugin.common.utils.RandomUtil;
import com.vhall.component.service.account.AdminAuthService;
import com.vhall.component.service.account.UserTicketService;
import com.vhall.component.service.rbac.RbacRoleActionService;
import com.vhall.component.service.rbac.RbacRoleMenuService;
import com.vhall.component.service.rbac.RbacRoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @author dalong
 * @date 2021-05-19 20:42
 */
@Service
public class AdminAuthServiceImpl implements AdminAuthService {

    @Autowired
    private AccountAdminsMapper adminsMapper;

    @Autowired
    private RbacRoleService roleService;

    @Autowired
    private RbacRoleMenuService roleMenuService;

    @Autowired
    private RbacRoleActionService rbacActionInnerFacade;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private UserTicketService userTicketService;
    /**
     * 是否开启房间审核
     * 1为开启
     * 0为关闭房间审核
     */
    @Value("${project.room.audit:0}")
    private Integer roomAuditWitch;

    @Override
    public AdminAuthLoginRspVO login(AdminAuthLoginReqVO reqVO) {
        AdminAuthLoginRspVO adminAuthLoginRspVO = new AdminAuthLoginRspVO();

        // 账号校验
        LambdaQueryWrapper<AdminsEntity> where = Wrappers.lambdaQuery();
        where.eq(AdminsEntity::getAdminName, reqVO.getAdminName())
                .isNull(AdminsEntity::getDeletedAt)
                .last("LIMIT 1");
        AdminsEntity adminsEntity = adminsMapper.selectOne(where);
        if (adminsEntity == null) {
            throw new BusinessException(BizErrorCode.EMPTY_ADMIN);
        }
        Digester sha256 = new Digester(DigestAlgorithm.SHA256);
        String md5PassWord = sha256.digestHex(reqVO.getPassword() + adminsEntity.getSalt());
        // 密码校验
        if (!adminsEntity.getPassword().equals(md5PassWord)) {
            throw new BusinessException(BizErrorCode.AUTH_PASSWORD_ERROR);
        }
        // 状态检测
        if (Constants.STATUS_DISABLED.equals(adminsEntity.getStatus())) {
            throw new BusinessException(BizErrorCode.BIZ_ADMIN_DISABLE);
        }
        // 角色检查
        if (adminsEntity.getRoleId() == null) {
            throw new BusinessException(BizErrorCode.BIZ_ROLE_NOT_EXIST);
        }
        RoleVO roleVO = roleService.getInfoById(adminsEntity.getRoleId());
        if (roleVO == null) {
            throw new BusinessException(BizErrorCode.BIZ_ROLE_NOT_EXIST);
        }

        // 查询菜单数据
        List<MenuesVO> menuEntities = roleMenuService.getListByRoleId(roleVO.getRoleId());
        // 查询actions
        List<ActionsVO> actionsVos = rbacActionInnerFacade.listActionByRoleId(roleVO.getRoleId());

        // 刷新token
        String token = createLoginToken(adminsEntity.getAdminId().toString());
        adminsEntity.setToken(token);
        adminsEntity.setTokenExpire(LocalDateTime.now().plusDays(1));
        String cacheValue = JSON.toJSONString(adminsEntity);
        redisTemplate.opsForValue().set(RedisKey.AUTH_TOKEN + adminsEntity.getToken(), cacheValue,
                AccountConstant.AMIN_TOKEN_TIME, TimeUnit.SECONDS);
        // 更新登录次数
        adminsEntity.setLoginNum(adminsEntity.getLoginNum() + 1);
        adminsEntity.setLastTime(adminsEntity.getUpdatedAt());
        adminsEntity.setUpdatedAt(LocalDateTime.now());
        adminsMapper.updateById(adminsEntity);
        // 格式化返回数据
        Map<String, Object> roleMap = new HashMap<>(2);
        roleMap.put("role_id", roleVO.getRoleId());
        roleMap.put("name", roleVO.getName());
        roleMap.put("desc", roleVO.getDesc());
        roleMap.put("status", roleVO.getStatus());
        roleMap.put("app_id", roleVO.getAppId());
        roleMap.put("level", roleVO.getLevel());
        roleMap.put("updated_at", roleVO.getUpdatedAt());
        roleMap.put("created_at", roleVO.getCreatedAt());
        roleMap.put("deleted_at", roleVO.getDeletedAt());
        roleMap.put("status_str", roleVO.getStatus().equals(1) ? "开启" : "关闭");
        roleMap.put("menues", menuEntities);
        roleMap.put("actions", actionsVos);
        adminAuthLoginRspVO.setRole(roleMap);
        adminAuthLoginRspVO.setAdminId(adminsEntity.getAdminId());
        adminAuthLoginRspVO.setAdminName(adminsEntity.getAdminName());
        adminAuthLoginRspVO.setNickName(adminsEntity.getNickName());
        adminAuthLoginRspVO.setToken(token);
        adminAuthLoginRspVO.setRoomAuditWitch(roomAuditWitch);
        UserTicketVO userTicket = new UserTicketVO();
        UserTicketWrapper userTicketWrapper = userTicketService.createUserTicket(adminAuthLoginRspVO.getAdminId().longValue());
        if (Objects.nonNull(userTicketWrapper)) {
            userTicket.setSecretKey(userTicketWrapper.getWebTicket().getC3Key());
            userTicket.setSecretIv(userTicketWrapper.getWebTicket().getC3Iv());
            userTicket.setTicket(userTicketWrapper.getWebTicket().getC3());
            adminAuthLoginRspVO.setUserTicket(userTicket);
        }

        return adminAuthLoginRspVO;
    }

    @Override
    public boolean logOut(AdminAuthLogOutReqVO logOutReqVO) {
        // 记录当前IP
        HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();

        AdminsEntity ads = new AdminsEntity();
        ads.setAdminId(logOutReqVO.getId());
        ads.setLastIp(request.getRemoteAddr());
        adminsMapper.updateById(ads);
        return redisTemplate.delete(RedisKey.AUTH_TOKEN + TokenThreadLocal.getToken().getToken());
    }


    /**
     * 生成token
     *
     * @param keyword 标记
     * @return
     */
    private String createLoginToken(String keyword) {
        // 生成token
        String tokenString = RandomUtil.getRandomNum(1000, 9999) + keyword + RandomUtil.getRandomNum(1000, 9999);
        return MD5.create().digestHex16(tokenString);

    }
}
